home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 23 / Amiga Format AFCD23 (Feb 1998, Issue 107).iso / -seriously_amiga- / shareware / programming / c / asyncio / src / openasyncfh.c < prev    next >
C/C++ Source or Header  |  1997-12-01  |  6KB  |  218 lines

  1. #include "async.h"
  2.  
  3.  
  4. #ifdef ASIO_NOEXTERNALS
  5. AsyncFile*
  6. AS_OpenAsyncFH(
  7.     BPTR handle,
  8.     OpenModes mode,
  9.     LONG bufferSize,
  10.     BOOL closeIt,
  11.     struct ExecBase *SysBase,
  12.     struct DosLibrary *DOSBase )
  13. #else
  14. AsyncFile *
  15. AS_OpenAsyncFH( BPTR handle, OpenModes mode, LONG bufferSize, BOOL closeIt )
  16. #endif
  17. {
  18.     struct FileHandle    *fh;
  19.     AsyncFile        *file = NULL;
  20.     BPTR    lock = NULL;
  21.     LONG    blockSize, blockSize2;
  22.     D_S( struct InfoData, infoData );
  23.  
  24.     if( mode == MODE_READ )
  25.     {
  26.         if( handle )
  27.         {
  28.             lock = DupLockFromFH( handle );
  29.         }
  30.     }
  31.     else
  32.     {
  33.         if( mode == MODE_APPEND )
  34.         {
  35.             /* in append mode, we open for writing, and then seek to the
  36.              * end of the file. That way, the initial write will happen at
  37.              * the end of the file, thus extending it
  38.              */
  39.  
  40.             if( handle )
  41.             {
  42.                 if( Seek( handle, 0, OFFSET_END ) < 0 )
  43.                 {
  44.                     if( closeIt )
  45.                     {
  46.                         Close( handle );
  47.                     }
  48.  
  49.                     handle = NULL;
  50.                 }
  51.             }
  52.         }
  53.  
  54.         /* we want a lock on the same device as where the file is. We can't
  55.          * use DupLockFromFH() for a write-mode file though. So we get sneaky
  56.          * and get a lock on the parent of the file
  57.          */
  58.         if( handle )
  59.         {
  60.             lock = ParentOfFH( handle );
  61.         }
  62.     }
  63.  
  64.     if( handle )
  65.     {
  66.         /* if it was possible to obtain a lock on the same device as the
  67.          * file we're working on, get the block size of that device and
  68.          * round up our buffer size to be a multiple of the block size.
  69.          * This maximizes DMA efficiency.
  70.          */
  71.  
  72.         blockSize = 512;
  73.         blockSize2 = 1024;
  74.  
  75.         if( lock )
  76.         {
  77.             if( Info( lock, infoData ) )
  78.             {
  79.                 blockSize = infoData->id_BytesPerBlock;
  80.                 blockSize2 = blockSize * 2;
  81.                 bufferSize = ( ( bufferSize + blockSize2 - 1 ) / blockSize2 ) * blockSize2;
  82.             }
  83.  
  84.             UnLock(lock);
  85.         }
  86.  
  87.         /* now allocate the ASyncFile structure, as well as the read buffers.
  88.          * Add 15 bytes to the total size in order to allow for later
  89.          * quad-longword alignement of the buffers
  90.          */
  91.  
  92.         for( ;; )
  93.         {
  94.             if( file = AllocVec( sizeof( AsyncFile ) + bufferSize + 15, MEMF_PUBLIC | MEMF_ANY ) )
  95.             {
  96.                 break;
  97.             }
  98.             else
  99.             {
  100.                 if( bufferSize > blockSize2 )
  101.                 {
  102.                     bufferSize -= blockSize2;
  103.                 }
  104.                 else
  105.                 {
  106.                     break;
  107.                 }
  108.             }
  109.         }
  110.  
  111.         if( file )
  112.         {
  113.             file->af_File        = handle;
  114.             file->af_ReadMode    = ( mode == MODE_READ );
  115.             file->af_BlockSize    = blockSize;
  116.             file->af_CloseFH    = closeIt;
  117.  
  118.             /* initialize the ASyncFile structure. We do as much as we can here,
  119.              * in order to avoid doing it in more critical sections
  120.              *
  121.              * Note how the two buffers used are quad-longword aligned. This
  122.              * helps performance on 68040 systems with copyback cache. Aligning
  123.              * the data avoids a nasty side-effect of the 040 caches on DMA.
  124.              * Not aligning the data causes the device driver to have to do
  125.              * some magic to avoid the cache problem. This magic will generally
  126.              * involve flushing the CPU caches. This is very costly on an 040.
  127.              * Aligning things avoids the need for magic, at the cost of at
  128.              * most 15 bytes of ram.
  129.              */
  130.  
  131.             fh            = BADDR( file->af_File );
  132.             file->af_Handler    = fh->fh_Type;
  133.             file->af_BufferSize    = ( ULONG ) bufferSize / 2;
  134.             file->af_Buffers[ 0 ]    = ( APTR ) ( ( ( ULONG ) file + sizeof( AsyncFile ) + 15 ) & 0xfffffff0 );
  135.             file->af_Buffers[ 1 ]    = file->af_Buffers[ 0 ] + file->af_BufferSize;
  136.             file->af_CurrentBuf    = 0;
  137.             file->af_SeekOffset    = 0;
  138.             file->af_PacketPending    = FALSE;
  139.             file->af_SeekPastEOF    = FALSE;
  140. #ifdef ASIO_NOEXTERNALS
  141.             file->af_SysBase    = SysBase;
  142.             file->af_DOSBase    = DOSBase;
  143. #endif
  144.  
  145.             /* this is the port used to get the packets we send out back.
  146.              * It is initialized to PA_IGNORE, which means that no signal is
  147.              * generated when a message comes in to the port. The signal bit
  148.              * number is initialized to SIGB_SINGLE, which is the special bit
  149.              * that can be used for one-shot signalling. The signal will never
  150.              * be set, since the port is of type PA_IGNORE. We'll change the
  151.              * type of the port later on to PA_SIGNAL whenever we need to wait
  152.              * for a message to come in.
  153.              *
  154.              * The trick used here avoids the need to allocate an extra signal
  155.              * bit for the port. It is quite efficient.
  156.              */
  157.  
  158.             file->af_PacketPort.mp_MsgList.lh_Head        = ( struct Node * ) &file->af_PacketPort.mp_MsgList.lh_Tail;
  159.             file->af_PacketPort.mp_MsgList.lh_Tail        = NULL;
  160.             file->af_PacketPort.mp_MsgList.lh_TailPred    = ( struct Node * ) &file->af_PacketPort.mp_MsgList.lh_Head;
  161.             file->af_PacketPort.mp_Node.ln_Type        = NT_MSGPORT;
  162.             /* MH: Avoid problems with SnoopDos */
  163.             file->af_PacketPort.mp_Node.ln_Name        = NULL;
  164.             file->af_PacketPort.mp_Flags            = PA_IGNORE;
  165.             file->af_PacketPort.mp_SigBit            = SIGB_SINGLE;
  166.             file->af_PacketPort.mp_SigTask            = FindTask( NULL );
  167.  
  168.             file->af_Packet.sp_Pkt.dp_Link            = &file->af_Packet.sp_Msg;
  169.             file->af_Packet.sp_Pkt.dp_Arg1            = fh->fh_Arg1;
  170.             file->af_Packet.sp_Pkt.dp_Arg3            = file->af_BufferSize;
  171.             file->af_Packet.sp_Pkt.dp_Res1            = 0;
  172.             file->af_Packet.sp_Pkt.dp_Res2            = 0;
  173.             file->af_Packet.sp_Msg.mn_Node.ln_Name        = ( STRPTR ) &file->af_Packet.sp_Pkt;
  174.             file->af_Packet.sp_Msg.mn_Node.ln_Type        = NT_MESSAGE;
  175.             file->af_Packet.sp_Msg.mn_Length        = sizeof( struct StandardPacket );
  176.  
  177.             if( mode == MODE_READ )
  178.             {
  179.                 /* if we are in read mode, send out the first read packet to
  180.                  * the file system. While the application is getting ready to
  181.                  * read data, the file system will happily fill in this buffer
  182.                  * with DMA transfers, so that by the time the application
  183.                  * needs the data, it will be in the buffer waiting
  184.                  */
  185.  
  186.                 file->af_Packet.sp_Pkt.dp_Type    = ACTION_READ;
  187.                 file->af_BytesLeft        = 0;
  188.  
  189.                 /* MH: We set the offset to the buffer not being filled, in
  190.                  * order to avoid special case code in SeekAsync. ReadAsync
  191.                  * isn't affected by this, since af_BytesLeft == 0.
  192.                  */
  193.                 file->af_Offset = file->af_Buffers[ 1 ];
  194.  
  195.                 if( file->af_Handler )
  196.                 {
  197.                     AS_SendPacket( file, file->af_Buffers[ 0 ] );
  198.                 }
  199.             }
  200.             else
  201.             {
  202.                 file->af_Packet.sp_Pkt.dp_Type    = ACTION_WRITE;
  203.                 file->af_BytesLeft        = file->af_BufferSize;
  204.                 file->af_Offset            = file->af_Buffers[ 0 ];
  205.             }
  206.         }
  207.         else
  208.         {
  209.             if( closeIt )
  210.             {
  211.                 Close( handle );
  212.             }
  213.         }
  214.     }
  215.  
  216.     return( file );
  217. }
  218.